﻿using Admin.NET.Application.Entity;
using Admin.NET.Application.Enums;
using Admin.NET.Application.Service.ModbusTcp;
using Admin.NET.Application.Service.ModbusTcpService;
using Admin.NET.Core.Service;
using AngleSharp.Dom;
using DocumentFormat.OpenXml.Presentation;
using DotNetty.Common.Internal;
using Microsoft.AspNetCore.Http;
using static Admin.NET.Application.Service.ModbusTcpService.ModbusTcpService;

namespace Admin.NET.Application;

/// <summary>
/// 设备信息服务
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class DeviceInfoService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<DeviceInfo> _deviceInfoRep;
    private readonly SqlSugarRepository<DeviceTemplateInfo> _deviceTemplateInfoRep;
    private readonly SqlSugarRepository<DeviceRelSlave> _reviceRelSlave;
    private readonly SqlSugarRepository<DeviceGateWay> deviceGateWayRep;
    private readonly DeviceOnOffLineService deviceOnOffLineService;
    private readonly ModbusInfoManager modbusInfoManager;

    public DeviceInfoService(SqlSugarRepository<DeviceInfo> deviceInfoRep, SqlSugarRepository<DeviceTemplateInfo> deviceTemplateInfoRep, SqlSugarRepository<DeviceRelSlave> reviceRelSlave, SqlSugarRepository<DeviceGateWay> deviceGateWayRep, DeviceOnOffLineService deviceOnOffLineService, ModbusInfoManager modbusInfoManager)
    {
        _deviceInfoRep = deviceInfoRep;
        this._deviceTemplateInfoRep = deviceTemplateInfoRep;
        this._reviceRelSlave = reviceRelSlave;
        this.deviceGateWayRep = deviceGateWayRep;
        this.deviceOnOffLineService = deviceOnOffLineService;
        this.modbusInfoManager = modbusInfoManager;
    }

    /// <summary>
    /// 分页查询设备信息
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Page")]
    [DisplayName("分页查询设备信息")]
    public async Task<SqlSugarPagedList<DeviceInfoOutput>> Page(PageDeviceInfoInput input)
    {
        input.SearchKey = input.SearchKey?.Trim();
        var query = _deviceInfoRep.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
                u.DeviceName.Contains(input.SearchKey)
                || u.DeviceNo.Contains(input.SearchKey)
                || u.Description.Contains(input.SearchKey)
                || u.Address.Contains(input.SearchKey)
                || u.Position.Contains(input.SearchKey)
            )
            .WhereIF(!string.IsNullOrWhiteSpace(input.DeviceName), u => u.DeviceName.Contains(input.DeviceName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.DeviceNo), u => u.DeviceNo.Contains(input.DeviceNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Description), u => u.Description.Contains(input.Description.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Address), u => u.Address.Contains(input.Address.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Position), u => u.Position.Contains(input.Position.Trim()))
            .WhereIF(input.DeviceGateWayId > 0, u => u.DeviceGateWayId == input.DeviceGateWayId)
            .WhereIF(input.DeviceTemplateInfoId > 0, u => u.DeviceTemplateInfoId == input.DeviceTemplateInfoId)
            .WhereIF(input.OrgId > 0, u => u.OrgId == input.OrgId)
            //处理外键和TreeSelector相关字段的连接
            .LeftJoin<DeviceGateWay>((u, devicegatewayid) => u.DeviceGateWayId == devicegatewayid.Id)
            .LeftJoin<DeviceTemplateInfo>((u, devicegatewayid, devicetemplateinfoid) => u.DeviceTemplateInfoId == devicetemplateinfoid.Id)
            .LeftJoin<SysOrg>((u, devicegatewayid, devicetemplateinfoid, orgid) => u.OrgId == orgid.Id)
            .Select((u, devicegatewayid, devicetemplateinfoid, orgid) => new DeviceInfoOutput
            {
                Id = u.Id,
                DeviceName = u.DeviceName,
                DeviceNo = u.DeviceNo,
                Description = u.Description,
                Address = u.Address,
                Position = u.Position,
                DevicePositionType = u.DevicePositionType,
                ImageUrl = u.ImageUrl,
                DeviceGateWayId = u.DeviceGateWayId,
                DeviceGateWayIdGateWayName = devicegatewayid.GateWayName,
                DeviceTemplateInfoId = u.DeviceTemplateInfoId,
                DeviceTemplateInfoIdTemplateName = devicetemplateinfoid.TemplateName,
                OrgId = u.OrgId,
                OrgIdName = orgid.Name,
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
            });
        var pageList = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
        foreach (var item in pageList.Items)
        {
            var connectDeviceInfo = modbusInfoManager.GetModbusConnectInfoByDeviceId(item.Id);
            var deviceInfo = connectDeviceInfo.Item2;
            var connectInfo = connectDeviceInfo.Item1;

            if (connectInfo != null && connectInfo.ModbusConnectStatus == Service.ModbusTcp.ModbusConnectStatus.Connected)
            {
                item.Active = Active.Activated;
            }
            else
            {
                item.Active = Active.NotActive;
            }
        }

        return pageList;
    }

    /// <summary>
    /// 增加设备信息
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Add")]
    [DisplayName("增加设备信息")]
    public async Task<long> Add(AddDeviceInfoInput input)
    {
        var entity = input.Adapt<DeviceInfo>();
        // 判断 网关Id有没有被绑定到其他设备过
        if (input.DeviceGateWayId > 0)
        {
            var gateWayDevice = await _deviceInfoRep.GetFirstAsync(u => u.DeviceGateWayId == input.DeviceGateWayId);
            if (gateWayDevice != null)
            {
                throw Oops.Oh(DeviceErrorCodeEnum.GatewayHasBinUsed);
            }
        }
        entity.ImageUrl = "";
        //获取entity 里的设备模板里的所有从机
        var deviceTemplateInfo = await _deviceTemplateInfoRep.AsQueryable().Includes(u => u.DeviceSlaveTemplates).FirstAsync(u => u.Id == entity.DeviceTemplateInfoId);
        await _deviceInfoRep.InsertAsync(entity);
        return entity.Id;
    }

    /// <summary>
    /// 删除设备信息
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Delete")]
    [DisplayName("删除设备信息")]
    public async Task Delete(DeleteDeviceInfoInput input)
    {
        var entity = await _deviceInfoRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        // 删除设备的时候删除所有的真实从机DeviceRelSlaves
        // 获取设备下所有的真实从机 DeviceRelSlaves
        var deviceRelSlaves = await _reviceRelSlave.AsQueryable()
            .Where(drs => drs.DeviceInfoId == entity.Id)
            .ToListAsync();

        // 删除所有的真实从机 DeviceRelSlaves
        if (deviceRelSlaves.Any())
        {
            await _reviceRelSlave.DeleteAsync(deviceRelSlaves);
        }
        //await _deviceInfoRep.FakeDeleteAsync(entity);   //假删除
        await _deviceInfoRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 更新设备信息
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Update")]
    [DisplayName("更新设备信息")]
    public async Task Update(UpdateDeviceInfoInput input)
    {
        var entity = input.Adapt<DeviceInfo>();
        // 判断 网关Id有没有被绑定到其他设备过
        if (input.DeviceGateWayId > 0)
        {
            var gateWayDevice = await _deviceInfoRep.GetFirstAsync(u => u.DeviceGateWayId == input.DeviceGateWayId && u.Id != entity.Id);

            if (gateWayDevice != null)
            {
                throw Oops.Oh(DeviceErrorCodeEnum.GatewayHasBinUsed);
            }
        }
        await _deviceInfoRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
        if (input.DeviceRelSlaves != null)
        {
            foreach (var item in input.DeviceRelSlaves)
            {
                await _reviceRelSlave.AsUpdateable(item).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
            }
        }
    }

    [HttpPost]
    [ApiDescriptionSettings(Name = "UpdateSlaves")]
    [DisplayName("更新设备从机信息")]
    public async Task UpdateSlaves(UpdateDeviceInfoInput input)
    {
        //获取设备下所有的 DeviceRelSlave
        var deviceRelSlaves = await _reviceRelSlave.AsQueryable().Where(u => u.DeviceInfoId == input.Id).ToListAsync();
        //删除设备下所有的 DeviceRelSlave
        await _reviceRelSlave.DeleteAsync(deviceRelSlaves);
        //获取模板下的所有从机
        var deviceTemplateInfo = await _deviceTemplateInfoRep.AsQueryable().Includes(u => u.DeviceSlaveTemplates).FirstAsync(u => u.Id == input.DeviceTemplateInfoId);

        //更新deviceInfo下的设备模板Id

        //插入新的 DeviceRelSlave
        if (deviceTemplateInfo != null && deviceTemplateInfo.DeviceSlaveTemplates.Count > 0)
        {
            foreach (var item in deviceTemplateInfo.DeviceSlaveTemplates)
            {
                var deviceRelSlave = new DeviceRelSlave
                {
                    DeviceInfoId = input.Id,
                    DeviceSlaveTemplateId = item.Id,
                    ComIdx = 1,
                    SlaveAddr = 1,
                    SlaveIp = "",
                    SlavePort = 1
                };

                input.DeviceRelSlaves?.Add(deviceRelSlave);
                await _reviceRelSlave.InsertAsync(deviceRelSlave);
            }
        }

        //更新deviceInfo下的设备模板Id
        var deviceInfo = await _deviceInfoRep.GetFirstAsync(u => u.Id == input.Id);
        if (deviceInfo != null)
        {
            deviceInfo.DeviceTemplateInfoId = input.DeviceTemplateInfoId;
            await _deviceInfoRep.UpdateAsync(deviceInfo);
        }
    }

    /// <summary>
    /// 获取设备信息
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Detail")]
    [DisplayName("获取设备信息")]
    public async Task<DeviceInfo> Detail([FromQuery] QueryByIdDeviceInfoInput input)
    {
        var re = await _deviceInfoRep.CopyNew().AsQueryable().Where(u => u.Id == input.Id).Includes(u => u.DeviceGateWay).Includes(u => u.DeviceTemplateInfo, temp => temp.DeviceSlaveTemplates).FirstAsync();

        // 查询 DeviceRelSlaves 及其相关的 DeviceSlaveTemplate 和 DeviceSlaveTemplatePoint
        re.DeviceRelSlaves = await _reviceRelSlave.CopyNew().AsQueryable()
            .Where(relSlave => relSlave.DeviceInfoId == re.Id)
            .Includes(relSlave => relSlave.DeviceSlaveTemplate, template => template.DeviceSlaveTemplatePoint)
            .ToListAsync();

        var deleteList = new List<DeviceRelSlave>();
        if (re.DeviceTemplateInfo == null)
        {
            return re;
        }
        foreach (var item in re.DeviceRelSlaves)
        {
            if (!re.DeviceTemplateInfo.DeviceSlaveTemplates.Any(u => u.Id == item.DeviceSlaveTemplateId))
            {
                deleteList.Add(item);
            }
        }

        for (int i = 0; i < deleteList.Count; i++)
        {
            var item = deleteList[i];
            re.DeviceRelSlaves.Remove(item);
        }

        return re;
    }

    /// <summary>
    /// 获取设备信息列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "List")]
    [DisplayName("获取设备信息列表")]
    public async Task<List<DeviceInfoOutput>> List([FromQuery] PageDeviceInfoInput input)
    {
        return await _deviceInfoRep.AsQueryable().Select<DeviceInfoOutput>().ToListAsync();
    }

    /// <summary>
    /// 获取设备网关ID列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "DeviceGateWayDeviceGateWayIdDropdown"), HttpGet]
    [DisplayName("获取设备网关ID列表")]
    public async Task<dynamic> DeviceGateWayDeviceGateWayIdDropdown()
    {
        return await _deviceInfoRep.Context.Queryable<DeviceGateWay>()
                .Select(u => new
                {
                    Label = u.GateWayName,
                    Value = u.Id
                }
                ).ToListAsync();
    }

    /// <summary>
    /// 获取设备模板ID列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "DeviceTemplateInfoDeviceTemplateInfoIdDropdown"), HttpGet]
    [DisplayName("获取设备模板ID列表")]
    public async Task<dynamic> DeviceTemplateInfoDeviceTemplateInfoIdDropdown()
    {
        return await _deviceInfoRep.Context.Queryable<DeviceTemplateInfo>()
                .Select(u => new
                {
                    Label = u.TemplateName,
                    Value = u.Id
                }
                ).ToListAsync();
    }

    [HttpGet("SysOrgTree")]
    [DisplayName("获取SysOrgTree")]
    public async Task<dynamic> SysOrgTree()
    {
        return await _deviceInfoRep.Context.Queryable<SysOrg>().ToTreeAsync(u => u.Children, u => u.Pid, 0);
    }

    [HttpGet]
    [ApiDescriptionSettings(Name = "RefreshAllDevice")]
    [DisplayName("更新在线的设备信息")]
    public async Task RefreshAllDevice()
    {
        //获取所有在线设备
        //var devices = await _deviceInfoRep.AsQueryable().ToListAsync();
        //foreach (var device in devices)
        //{
        //    await modbusInfoManager.RefreshDeviceByDeviceId(device.Id);
        //}
        var info = await GetAllDeviceInfo();
        await modbusInfoManager.RefreshDeviceByDeviceId(info);
    }

    [HttpGet]
    [ApiDescriptionSettings(Name = "RefreshAllDeviceById")]
    [DisplayName("更新在线的设备信息ById")]
    public async Task RefreshAllDeviceById(long id)
    {
        var info = await GetAllDeviceInfo();
        await modbusInfoManager.RefreshDeviceByDeviceId(info);
    }

    [NonAction]
    public async Task<List<DeviceInfo>> GetAllDeviceInfo()
    {
        var deviceInfoRep = _deviceInfoRep.CopyNew();
        var deviceGateWayRep = this.deviceGateWayRep.CopyNew();
        // 获取所有网关
        var gateWays = await deviceGateWayRep.GetListAsync();
        var deviceInfos = new List<DeviceInfo>();
        foreach (var gateWay in gateWays)
        {
            var DeviceInfoTemp = await deviceInfoRep.GetFirstAsync(u => u.DeviceGateWayId == gateWay.Id);
            if (DeviceInfoTemp == null)
            {
                continue;
            }
            var DeviceInfo = await Detail(new QueryByIdDeviceInfoInput { Id = DeviceInfoTemp.Id });
            if (DeviceInfo == null)
            {
                continue;
            }

            //获取设备下的所有真实从机
            var deviceRelSlaves = DeviceInfo.DeviceRelSlaves;
            foreach (var item in deviceRelSlaves)
            {
                var temp = item.DeviceSlaveTemplate;
                var point = await deviceInfoRep.Context.Queryable<DeviceSlaveTemplatePoints>()
                    .Where(u => u.DeviceSlaveTemplateId == temp.Id)
                    .ToListAsync();
                temp.DeviceSlaveTemplatePoint = point;
            }
            var pointValues = await deviceInfoRep.Context.Queryable<DevicePointsValue>()
                .Where(x => x.DeviceInfoId == DeviceInfo.Id)
                .ToListAsync();
            // 删除pointValues中不在deviceRelSlaves里的DeviceSlaveTemplate下的DeviceSlaveTemplatePoint
            // 获取所有的 DeviceSlaveTemplatePoint Id
            var validPointIds = deviceRelSlaves
                .SelectMany(x => x.DeviceSlaveTemplate.DeviceSlaveTemplatePoint)
                .Select(p => p.Id)
                .ToHashSet();
            var invalidPointValues = pointValues
                .Where(item => !validPointIds.Contains(item.DeviceSlaveTemplatePointsId))
                .ToList();
            if (invalidPointValues.Count > 0)
            {
                await deviceInfoRep.Context.Deleteable<DevicePointsValue>()
                    .Where(pv => invalidPointValues.Any(item => item.DeviceSlaveTemplatePointsId == pv.DeviceSlaveTemplatePointsId))
                    .ExecuteCommandAsync();
            }

            var validPoints = deviceRelSlaves
               .SelectMany(x => x.DeviceSlaveTemplate.DeviceSlaveTemplatePoint)
               .ToList();
            var missingPointValues = validPoints
                .Where(validPoint => !pointValues.Any(pv => pv.DeviceSlaveTemplatePointsId == validPoint.Id))
                .Select(validPoint => new DevicePointsValue
                {
                    DeviceSlaveTemplatePointsId = validPoint.Id,
                    DeviceInfoId = DeviceInfo.Id,
                    PonitValue = ""
                    // 你可以在这里设置其他需要的属性
                })
                .ToList();
            if (missingPointValues.Count > 0)
            {
                await deviceInfoRep.Context.Insertable(missingPointValues).ExecuteCommandAsync();
            }

            //将pointValues 的值对应赋值给 DeviceSlaveTemplatePoints里的datavalue
            foreach (var item in deviceRelSlaves)
            {
                foreach (var point in item.DeviceSlaveTemplate.DeviceSlaveTemplatePoint)
                {
                    var tempPoint = pointValues.FirstOrDefault(u => u.DeviceSlaveTemplatePointsId == point.Id);
                    if (tempPoint != null)
                    {
                        point.DataValue = tempPoint.PonitValue;
                    }
                }
            }

            DeviceInfo.DeviceGateWay = gateWay;
            DeviceInfo.DeviceRelSlaves = deviceRelSlaves;
            deviceInfos.Add(DeviceInfo);
        }
        return deviceInfos;
    }
}